#include <aura.h>
#include "private.h"
#include <sys/types.h>
#include <sys/time.h>
#ifdef _android
#include <sys/syscall.h>
#endif
#include <unistd.h>
#include <linux/unistd.h>
#include <linknode.h>
#include <signal.h>
#include <string.h>
#include <pthread.h>

#define gettid()  syscall(__NR_gettid)

ThreadDescr s_mainThreadDescr;
pid_t s_processId;

#define TLS_NUM (8)
//Aura_UInt32 s_slotValue[TLS_NUM] = {0};

Aura_Handle s_hThreadSlotLock = NULL;
struct timeval g_tvStartTime;

EXTERN_C Aura_ECode CreateModuleLock();
EXTERN_C void DestroyModuleLock();

Aura_UInt32 g_ThreadDescrSlot = (Aura_UInt32)(-1);

extern Aura_ECode SharedMemory_Initialize();
extern Aura_Void  SharedMemory_Destroy();

extern Aura_ECode VirtualMemory_Initialize();
extern Aura_Void  VirtualMemory_Destroy();

static
void SignalHandler (int sig, siginfo_t *si, void *ctx)
{
    switch(sig) {
    case SIG_ABORTTHREAD:
        AuraThread_Quit(0);
        break;
    default:
        Aura_printf("<%s> received signal(%d).\n",__FUNCTION__,sig);
        break;
    }
}

static
Aura_ECode InstallSignalHandler()
{
    struct sigaction sa;
    int res = 0;

    memset((void *)&sa, 0, sizeof(sa));
    sa.sa_sigaction = SignalHandler;
    sa.sa_flags = SA_SIGINFO;

    res = sigaction(SIG_ABORTTHREAD, &sa, NULL);
    if (res < 0) {
        return GetLastAuraECode();
    }
    return AURA_NOERROR;
}

void __attribute__((constructor)) Aura_Initialize()
{
    Aura_ECode ec = AURA_NOERROR;

    s_processId = getpid();
    s_mainThreadDescr.m_threadId = gettid();
    //s_mainThreadDescr.m_rawStack = (Aura_Address)-1;
    //s_mainThreadDescr.m_rawStackSize = 0;
    s_mainThreadDescr.m_hStartEvent = NULL;
    s_mainThreadDescr.m_bMainThread = AURA_TRUE;

    ec = AuraTls_Allocate(&g_ThreadDescrSlot);
    if (AURA_FAILED(ec)) {
        goto E_FAIL_EXIT;
    }
    ec = AuraTls_SetValue(g_ThreadDescrSlot, &s_mainThreadDescr);
    if (AURA_FAILED(ec)) {
        goto E_FAIL_EXIT;
    }

    ec = AuraEvent_Create(AURA_FALSE,
                    AURA_UNSIGNALED,
                    &s_mainThreadDescr.m_hQuitEvent);
    if (AURA_FAILED(ec)) {
        goto E_FAIL_EXIT;
    }

    //s_slotValue[0] = (Aura_UInt32)&s_mainThreadDescr;

    ec = AuraCriticalSection_Create(&s_hThreadSlotLock);
    if (AURA_FAILED(ec)) {
        goto E_FAIL_EXIT;
    }

    gettimeofday(&g_tvStartTime, 0);

    ec = CreateModuleLock();
    if (AURA_FAILED(ec)) {
        goto E_FAIL_EXIT;
    }

    ec = SharedMemory_Initialize();
    if (AURA_FAILED(ec)) {
        goto E_FAIL_EXIT;
    }
    ec = VirtualMemory_Initialize();
    if (AURA_FAILED(ec)) {
        goto E_FAIL_EXIT;
    }

    ec = InstallSignalHandler();
    if (AURA_FAILED(ec)) {
        goto E_FAIL_EXIT;
    }
    return ;

E_FAIL_EXIT:
    Aura_printf("<AURA> initalize failed. (ec:0x%x).\n",ec);
    return ;
}

void __attribute__((destructor)) Aura_Destroy()
{
//    VirtualMemory_Destroy();
//    SharedMemory_Destroy();
//    DestroyModuleLock();
//
//    if (NULL != s_hThreadSlotLock) {
//        AuraCriticalSection_Destroy(s_hThreadSlotLock);
//        s_hThreadSlotLock = NULL;
//    }
    return ;
}
